﻿using System.Text.RegularExpressions;

namespace Crux.Core.SQL.Formatter.Core;
/// <summary>
/// 
/// </summary>
public class Token
{
    /// <summary>
    /// 
    /// </summary>
    public readonly TokenTypes type;
    /// <summary>
    /// 
    /// </summary>
    public readonly string value;
    /// <summary>
    /// 
    /// </summary>
    public readonly string? regex;
    /// <summary>
    /// 
    /// </summary>
    public readonly string? whitespaceBefore;
    /// <summary>
    /// 
    /// </summary>
    public readonly string? key;
    /// <summary>
    /// 
    /// </summary>
    /// <param name="type"></param>
    /// <param name="value"></param>
    /// <param name="regex"></param>
    /// <param name="whitespaceBefore"></param>
    /// <param name="key"></param>
    public Token(TokenTypes type, string value, string? regex, string? whitespaceBefore, string? key)
    {
        this.type = type;
        this.value = value;
        this.regex = regex;
        this.whitespaceBefore = whitespaceBefore;
        this.key = key;
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="type"></param>
    /// <param name="value"></param>
    /// <param name="regex"></param>
    /// <param name="whitespaceBefore"></param>
    public Token(TokenTypes type, string value, string? regex, string? whitespaceBefore)
        : this(type, value, regex, whitespaceBefore, null) { }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="type"></param>
    /// <param name="value"></param>
    /// <param name="regex"></param>
    public Token(TokenTypes type, string value, string? regex)
        : this(type, value, regex, null) { }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="type"></param>
    /// <param name="value"></param>
    public Token(TokenTypes type, string value)
        : this(type, value, null) { }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="whitespaceBefore"></param>
    /// <returns></returns>
    public Token WithWhitespaceBefore(string whitespaceBefore)
    {
        return new Token(type, value, regex, whitespaceBefore, key);
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public Token WithKey(string key)
    {
        return new Token(type, value, regex, whitespaceBefore, key);
    }
    /// <summary>
    /// 
    /// </summary>
    /// <returns></returns>
    public override string ToString()
    {
        return "type: " + type + ", value: [" + value + "], regex: /" + regex + "/, key:" + key;
    }

    private static readonly Regex And =
        new Regex("^AND$", RegexOptions.IgnoreCase);
    private static readonly Regex Between =
        new Regex("^BETWEEN$", RegexOptions.IgnoreCase);
    private static readonly Regex Limit =
        new Regex("^LIMIT$", RegexOptions.IgnoreCase);
    private static readonly Regex Set =
        new Regex("^SET$", RegexOptions.IgnoreCase);
    private static readonly Regex By =
        new Regex("^BY$", RegexOptions.IgnoreCase);
    private static readonly Regex Window =
        new Regex("^WINDOW$", RegexOptions.IgnoreCase);
    private static readonly Regex End =
        new Regex("^END$", RegexOptions.IgnoreCase);

    private static Func<Token?, bool> IsToken(TokenTypes type, Regex regex)
    {
        return token => token?.type == type && regex.IsMatch(token.value);
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="token"></param>
    /// <returns></returns>
    public static bool IsAnd(Token token)
    {
        return IsToken(TokenTypes.RESERVED_NEWLINE, And).Invoke(token);
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="token"></param>
    /// <returns></returns>
    public static bool IsBetween(Token token)
    {
        return IsToken(TokenTypes.RESERVED, Between).Invoke(token);
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="token"></param>
    /// <returns></returns>
    public static bool IsLimit(Token? token)
    {
        return IsToken(TokenTypes.RESERVED_TOP_LEVEL, Limit).Invoke(token);
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="token"></param>
    /// <returns></returns>
    public static bool IsSet(Token token)
    {
        return IsToken(TokenTypes.RESERVED_TOP_LEVEL, Set).Invoke(token);
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="token"></param>
    /// <returns></returns>
    public static bool IsBy(Token token)
    {
        return IsToken(TokenTypes.RESERVED, By).Invoke(token);
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="token"></param>
    /// <returns></returns>
    public static bool IsWindow(Token token)
    {
        return IsToken(TokenTypes.RESERVED_TOP_LEVEL, Window).Invoke(token);
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="token"></param>
    /// <returns></returns>
    public static bool IsEnd(Token token)
    {
        return IsToken(TokenTypes.CLOSE_PAREN, End).Invoke(token);
    }
}